home *** CD-ROM | disk | FTP | other *** search
/ Software of the Month Club 2000 October / Software of the Month - Ultimate Collection Shareware 277.iso / pc / PROGRAMS / UTILITY / WINLINUX / DATA1.CAB / programs_-_kernel_source / FS / READDIR.C < prev    next >
Encoding:
C/C++ Source or Header  |  1999-09-17  |  4.2 KB  |  199 lines

  1. /*
  2.  *  linux/fs/readdir.c
  3.  *
  4.  *  Copyright (C) 1995  Linus Torvalds
  5.  */
  6.  
  7. #include <linux/sched.h>
  8. #include <linux/mm.h>
  9. #include <linux/errno.h>
  10. #include <linux/stat.h>
  11. #include <linux/file.h>
  12. #include <linux/smp_lock.h>
  13.  
  14. #include <asm/uaccess.h>
  15.  
  16. /*
  17.  * Traditional linux readdir() handling..
  18.  *
  19.  * "count=1" is a special case, meaning that the buffer is one
  20.  * dirent-structure in size and that the code can't handle more
  21.  * anyway. Thus the special "fillonedir()" function for that
  22.  * case (the low-level handlers don't need to care about this).
  23.  */
  24. #define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
  25. #define ROUND_UP(x) (((x)+sizeof(long)-1) & ~(sizeof(long)-1))
  26.  
  27. struct old_linux_dirent {
  28.     unsigned long    d_ino;
  29.     unsigned long    d_offset;
  30.     unsigned short    d_namlen;
  31.     char        d_name[1];
  32. };
  33.  
  34. struct readdir_callback {
  35.     struct old_linux_dirent * dirent;
  36.     int count;
  37. };
  38.  
  39. static int fillonedir(void * __buf, const char * name, int namlen, off_t offset, ino_t ino)
  40. {
  41.     struct readdir_callback * buf = (struct readdir_callback *) __buf;
  42.     struct old_linux_dirent * dirent;
  43.  
  44.     if (buf->count)
  45.         return -EINVAL;
  46.     buf->count++;
  47.     dirent = buf->dirent;
  48.     put_user(ino, &dirent->d_ino);
  49.     put_user(offset, &dirent->d_offset);
  50.     put_user(namlen, &dirent->d_namlen);
  51.     copy_to_user(dirent->d_name, name, namlen);
  52.     put_user(0, dirent->d_name + namlen);
  53.     return 0;
  54. }
  55.  
  56. asmlinkage int old_readdir(unsigned int fd, void * dirent, unsigned int count)
  57. {
  58.     int error;
  59.     struct file * file;
  60.     struct dentry * dentry;
  61.     struct inode * inode;
  62.     struct readdir_callback buf;
  63.  
  64.     lock_kernel();
  65.     error = -EBADF;
  66.     file = fget(fd);
  67.     if (!file)
  68.         goto out;
  69.  
  70.     dentry = file->f_dentry;
  71.     if (!dentry)
  72.         goto out_putf;
  73.  
  74.     inode = dentry->d_inode;
  75.     if (!inode)
  76.         goto out_putf;
  77.  
  78.     buf.count = 0;
  79.     buf.dirent = dirent;
  80.  
  81.     error = -ENOTDIR;
  82.     if (!file->f_op || !file->f_op->readdir)
  83.         goto out_putf;
  84.  
  85.     /*
  86.      * Get the inode's semaphore to prevent changes
  87.      * to the directory while we read it.
  88.      */
  89.     down(&inode->i_sem);
  90.     error = file->f_op->readdir(file, &buf, fillonedir);
  91.     up(&inode->i_sem);
  92.     if (error < 0)
  93.         goto out_putf;
  94.     error = buf.count;
  95.  
  96. out_putf:
  97.     fput(file);
  98. out:
  99.     unlock_kernel();
  100.     return error;
  101. }
  102.  
  103. /*
  104.  * New, all-improved, singing, dancing, iBCS2-compliant getdents()
  105.  * interface. 
  106.  */
  107. struct linux_dirent {
  108.     unsigned long    d_ino;
  109.     unsigned long    d_off;
  110.     unsigned short    d_reclen;
  111.     char        d_name[1];
  112. };
  113.  
  114. struct getdents_callback {
  115.     struct linux_dirent * current_dir;
  116.     struct linux_dirent * previous;
  117.     int count;
  118.     int error;
  119. };
  120.  
  121. static int filldir(void * __buf, const char * name, int namlen, off_t offset, ino_t ino)
  122. {
  123.     struct linux_dirent * dirent;
  124.     struct getdents_callback * buf = (struct getdents_callback *) __buf;
  125.     int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1);
  126.  
  127.     buf->error = -EINVAL;    /* only used if we fail.. */
  128.     if (reclen > buf->count)
  129.         return -EINVAL;
  130.     dirent = buf->previous;
  131.     if (dirent)
  132.         put_user(offset, &dirent->d_off);
  133.     dirent = buf->current_dir;
  134.     buf->previous = dirent;
  135.     put_user(ino, &dirent->d_ino);
  136.     put_user(reclen, &dirent->d_reclen);
  137.     copy_to_user(dirent->d_name, name, namlen);
  138.     put_user(0, dirent->d_name + namlen);
  139.     ((char *) dirent) += reclen;
  140.     buf->current_dir = dirent;
  141.     buf->count -= reclen;
  142.     return 0;
  143. }
  144.  
  145. asmlinkage int sys_getdents(unsigned int fd, void * dirent, unsigned int count)
  146. {
  147.     struct file * file;
  148.     struct dentry * dentry;
  149.     struct inode * inode;
  150.     struct linux_dirent * lastdirent;
  151.     struct getdents_callback buf;
  152.     int error;
  153.  
  154.     lock_kernel();
  155.     error = -EBADF;
  156.     file = fget(fd);
  157.     if (!file)
  158.         goto out;
  159.  
  160.     dentry = file->f_dentry;
  161.     if (!dentry)
  162.         goto out_putf;
  163.  
  164.     inode = dentry->d_inode;
  165.     if (!inode)
  166.         goto out_putf;
  167.  
  168.     buf.current_dir = (struct linux_dirent *) dirent;
  169.     buf.previous = NULL;
  170.     buf.count = count;
  171.     buf.error = 0;
  172.  
  173.     error = -ENOTDIR;
  174.     if (!file->f_op || !file->f_op->readdir)
  175.         goto out_putf;
  176.  
  177.     /*
  178.      * Get the inode's semaphore to prevent changes
  179.      * to the directory while we read it.
  180.      */
  181.     down(&inode->i_sem);
  182.     error = file->f_op->readdir(file, &buf, filldir);
  183.     up(&inode->i_sem);
  184.     if (error < 0)
  185.         goto out_putf;
  186.     error = buf.error;
  187.     lastdirent = buf.previous;
  188.     if (lastdirent) {
  189.         put_user(file->f_pos, &lastdirent->d_off);
  190.         error = count - buf.count;
  191.     }
  192.  
  193. out_putf:
  194.     fput(file);
  195. out:
  196.     unlock_kernel();
  197.     return error;
  198. }
  199.